<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>preview_demo</title>
    <link rel="stylesheet" type="text/css" href="public.css" />
  </head>
  <style>
    .container {
      height: 100%;
      width: 100%;
      overflow: hidden;
    }
    .operate {
      margin-top: 24px;
    }
    iframe {
      border: none;
    }
    .operate::after {
      content: '';
      display: block;
      clear: both;
    }

    .module {
      float: left;
      width: 340px;
      /*min-height: 320px;*/
      margin-left: 16px;
      padding: 16px 8px;
      box-sizing: border-box;
      border: 1px solid #e5e5e5;
    }

    .module .item {
      margin-bottom: 4px;
    }

    .module input[type='text'] {
      box-sizing: border-box;
      display: inline-block;
      vertical-align: middle;
      margin-left: 0;
      width: 150px;
      min-height: 20px;
    }

    .module .btn {
      min-width: 80px;
      min-height: 24px;
      margin-top: 100px;
      margin-left: 80px;
    }
  </style>

  <body onbeforeunload="onbeforeunload">
    <!--视频窗口展示-->
    <div id="playWnd" class="playWnd container"></div>
  </body>

  <!--三个必要的js文件引入-->
  <script src="jquery-1.12.4.min.js"></script>
  <script src="jsencrypt.min.js"></script>
  <!-- 用于RSA加密 -->
  <script src="jsWebControl-1.0.0.min.js"></script>
  <!-- 用于前端与插件交互 -->

  <script type="text/javascript">
    let w,
      h,
      offsetLeft,
      offsetTop,
      cut = {},
      oWebControl
    let list = {},
      config = {},
      scaleConfig = {} //视频参数
    //声明公用变量
    var initCount = 0
    var pubKey = ''

    let faterNodeId = null
    let areaId = null
    function loaded() {
      if (!faterNodeId) return
      window.parent.postMessage({
        message: {
          eventType: 'loaded',
          id: faterNodeId,
          index: Number(areaId?.split('_')[1])
        }
      })
    }
    function debounce(func, wait, promptly = false) {
      let timeout = null
      return function () {
        let context = this
        let args = arguments
        function clear() {
          timeout = undefined
        }
        function exec() {
          func.apply(context, args)
        }
        if (promptly && !timeout) {
          exec()
        }
        if (timeout) clearTimeout(timeout)
        timeout = setTimeout(promptly ? clear : exec, wait)
      }
    }

    const setSize = debounce(() => {
      if (!faterNodeId) return
      const rect = window.parent.document
        .getElementById(areaId + '_' + faterNodeId + '_plugin')
        .getBoundingClientRect()
      offsetLeft = rect.left
      offsetTop = rect.top
      w = rect.width * (scaleConfig.scaleX || 1)
      h = rect.height * (scaleConfig.scaleY || 1)
      resize()
    }, 10)
    function onbeforeunload() {
      window.removeEventListener('resize', setSize)
    }
    window.addEventListener('resize', setSize)
    // 监听父页面的消息
    window.addEventListener('message', function (e) {
      console.log('海康 iframe', e.data)
      if (e && e.data) {
        switch (e.data.action) {
          case 'init': //初始化
            //页面加载时创建播放实例初始化
            scaleConfig = e.data.scaleConfig || {}
            w = $(window).width() * (scaleConfig.scaleX || 1)
            h = $(window).height() * (scaleConfig.scaleY || 1)
            offsetLeft = e.data.iframeOffset.left
            offsetTop = e.data.iframeOffset.top

            var playWnd = document.getElementById('playWnd')
            setTimeout(() => {
              playWnd = document.getElementById('playWnd')
            }, 3000)
            list = e.data.list
            config = e.data.config
            faterNodeId = e.data.list.id
            areaId = e.data.list.areaId
            initPlugin()
            break
          case 'resize': // 父页面容器尺寸改变
            // try {
            //   scaleConfig = e.data.scaleConfig || {}
            //   w = $(window).width() * (scaleConfig.scaleX || 1)
            //   h = $(window).height() * (scaleConfig.scaleY || 1)
            //   offsetLeft = e.data.iframeOffset.left
            //   offsetTop = e.data.iframeOffset.top
            //   resize()
            // } catch (e) {
            // }
            setSize()
            break
          case 'allResize': // 全部重新resize
            window.parent.postMessage({
              message: {
                eventType: 'allResize',
                id: faterNodeId,
                index: Number(areaId?.split('_')[1])
              }
            })
            break
          case 'cut': //扣除部分窗体
            cut = e.data.cut
            if (cut && oWebControl) {
              oWebControl.JS_CuttingPartWindow(cut.x, cut.y, cut.w, cut.h)
            }
            break
          case 'repair': //还原扣除部分窗体
            if (cut && oWebControl) {
              oWebControl.JS_RepairPartWindow(0, 0, w, h)
            }
            break
          case 'destroy':
            destroy()
            break
          case 'hide':
            if (oWebControl) {
              oWebControl.JS_HideWnd()
            }
            break
          case 'show':
            if (oWebControl) {
              oWebControl.JS_ShowWnd()
            }
            break
          case 'playback':
            console.log('回放', e.data)
            list.startTime = e.data.startTime
            list.endTime = e.data.endTime
            list.isplayback = 0
            list.showToolbar = 1
            destroy(true)
            break
          case 'real':
            console.log('实时', e.data)
            list.isplayback = 1
            list.showToolbar = 0
            destroy(true)
            break
          case 'full':
            console.log('full')
            // 全屏 切换为主码流
            realtimeVideo(0)
            break
          case 'notFull':
            console.log('notFull')
            // 退出全屏 切换为子码流
            realtimeVideo(1)
            break
        }
      }
    })

    // 创建播放实例
    function initPlugin() {
      $('#svg').show()
      oWebControl = new WebControl({
        szPluginContainer: 'playWnd', // 指定容器id
        iServicePortStart: 15900, // 指定起止端口号，建议使用该值
        iServicePortEnd: 15909,
        szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
        cbConnectSuccess: function () {
          // 创建WebControl实例成功
          setSize()
          oWebControl
            .JS_StartService('window', {
              // WebControl实例创建成功后需要启动服务
              dllPath: './VideoPluginConnect.dll' // 值"./VideoPluginConnect.dll"写死
            })
            .then(
              function () {
                // 启动插件服务成功
                loaded()
                setCallbacks() //设置窗口消息控制回调

                oWebControl
                  .JS_CreateWnd('playWnd', w, h, { bEmbed: true })
                  .then(function () {
                    //JS_CreateWnd创建视频播放窗口，宽高可设定
                    init() // 创建播放实例成功后初始化
                  })
              },
              function () {
                // 启动插件服务失败
              }
            )
        },
        cbConnectError: function () {
          loaded()
          // 创建WebControl实例失败
          oWebControl = null
          $('#playWnd').html(
            "<p class='tip'>插件未启动，正在尝试启动，请稍候...</p>"
          )
          WebControl.JS_WakeUp('VideoWebPlugin://') // 程序未启动时执行error函数，采用wakeup来启动程序
          initCount++
          if (initCount < 3) {
            setTimeout(function () {
              initPlugin()
            }, 3000)
          } else {
            const host = location.host // 将插件放在当前网址根目录下
            $('#playWnd').html(
              `<div class='tip'><a  href='${host}/VideoWebPlugin.exe'>插件启动失败，请检查插件是否安装</a> <a onclick='initPlugin()' class='textBlue'>已安装</a></div>`
            )
          }
          $('#svg').hide()
        },
        cbConnectClose: function (bNormalClose) {
          loaded()
          // 异常断开：bNormalClose = false
          // JS_Disconnect正常断开：bNormalClose = true
          oWebControl = null
        }
      })
    }

    // 设置窗口控制回调
    function setCallbacks() {
      oWebControl.JS_SetWindowControlCallback({
        cbIntegrationCallBack: cbIntegrationCallBack
      })
    }

    // 推送消息
    function cbIntegrationCallBack(oData) {
      if (oData && oData.responseMsg && oData.responseMsg.type == 1) {
        // 窗口选中
        window.parent.postMessage(
          {
            action: 'videoClick',
            data: list
          },
          '*'
        )
      }
      showCBInfo(JSON.stringify(oData.responseMsg))
    }

    let clickCount = 0
    let clickStartTime = 0
    let isFull = false
    // 显示接口返回的消息及插件回调信息
    function showCBInfo(szInfo, type) {
      // 抓图
      // {
      // 	"msg": {
      // 		"cameraIndexCode": "50010901001310000814",
      // 		"expand": "C:/Program Files (x86)/VideoWebPlugin/SnapShot/16】马鞍溪进口道闸_1631600146918.jpg",
      // 		"result": 0,
      // 		"wndId": 1
      // 	},
      // 	"type": 3
      // }
      if (type === 'error') {
        console.error(szInfo)
      } else {
        const info = JSON.parse(szInfo)
        if (info.msg.result === 256) {
          if (clickCount === 0) {
            // 开始计时 500ms内再次点击就是双击
            clickCount = 1
            clickStartTime = new Date().getTime()
          } else {
            const clickEndTime = new Date().getTime()
            const time = clickEndTime - clickStartTime
            clickCount = 0
            if (time < 500) {
              isFull = !isFull
              window.parent.postMessage(
                {
                  action: 'dbClick',
                  data: list,
                  isFull
                },
                '*'
              )
            }
          }
        }
        if (info.msg.result === 1024) {
          isFull = true
        } else if (info.msg.result === 1025) {
          isFull = false
        }
        window.parent.postMessage({
          message: {
            szInfo,
            id: faterNodeId,
            index: Number(areaId?.split('_')[1])
          }
        })
      }
    }
    //初始化
    function init() {
      getPubKey(function () {
        ////////////////////////////////// 请自行修改以下变量值	////////////////////////////////////
        var appkey = config.APPKEY //综合安防管理平台提供的appkey，必填
        var secret = setEncrypt(config.SECRET || '') //综合安防管理平台提供的secret，必填
        var ip = config.ip //综合安防管理平台IP地址，必填
        var playMode = list.isplayback == 1 ? 0 : 1 //初始播放模式：0-预览，1-回放
        var port = (config.port || 443) * 1 //综合安防管理平台端口，若启用HTTPS协议，默认443
        var snapDir = config.SnapDir || '' //抓图存储路径 "D:\\SnapDir"
        var videoDir = config.videoDir || '' //紧急录像或录像剪辑存储路径 "D:\\VideoDir"
        var layout = '1x1' //playMode指定模式的布局
        var enableHTTPS = 1 //是否启用HTTPS协议与综合安防管理平台交互，这里总是填1
        var encryptedFields = 'secret' //加密字段，默认加密领域为secret
        var showToolbar = list.showToolbar == 0 ? 0 : 1 //是否显示工具栏，0-不显示，非0-显示
        var showSmart = list.showSmart == 1 ? 1 : 0 //是否显示智能信息（如配置移动侦测后画面上的线框），0-不显示，非0-显示
        // var showSmart = 0; //是否显示智能信息（如配置移动侦测后画面上的线框），0-不显示，非0-显示
        var buttonIDs =
          '0,16,256,257,258,259,260,512,513,514,515,516,517,768,769' //自定义工具条按钮
        ////////////////////////////////// 请自行修改以上变量值	////////////////////////////////////

        let params = {
          appkey: appkey, //API网关提供的appkey
          secret: secret, //API网关提供的secret
          ip: ip, //API网关IP地址
          playMode: playMode, //播放模式（决定显示预览还是回放界面）
          port: port, //端口
          snapDir: snapDir, //抓图存储路径
          videoDir: videoDir, //紧急录像或录像剪辑存储路径
          layout: layout, //布局
          enableHTTPS: enableHTTPS, //是否启用HTTPS协议
          encryptedFields: encryptedFields, //加密字段
          showToolbar: showToolbar, //是否显示工具栏
          showSmart: showSmart, //是否显示智能信息
          buttonIDs: buttonIDs //自定义工具条按钮
        }
        console.log('海康---初始化参数', params)
        oWebControl
          .JS_RequestInterface({
            funcName: 'init',
            argument: JSON.stringify(params)
          })
          .then(function (oData) {
            setSize() // 初始化后resize一次，规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
            if (list.isplayback == 1) {
              realtimeVideo()
            } else {
              playback()
            }
          })
      })
    }
    //实时
    function realtimeVideo(newStreamMode = 1) {
      var cameraIndexCode = list.deviceCode //获取输入的监控点编号值，必填
      var streamMode = newStreamMode //主子码流标识：0-主码流，1-子码流
      var transMode = 1 //传输协议：0-UDP，1-TCP
      var gpuMode = 0 //是否启用GPU硬解，0-不启用，1-启用
      var wndId = -1 //播放窗口序号（在2x2以上布局下可指定播放窗口）

      cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, '')
      cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, '')

      oWebControl.JS_RequestInterface({
        funcName: 'startPreview',
        argument: JSON.stringify({
          cameraIndexCode: cameraIndexCode, //监控点编号
          streamMode: streamMode, //主子码流标识
          transMode: transMode, //传输协议
          gpuMode: gpuMode, //是否开启GPU硬解
          wndId: wndId //可指定播放窗口
        })
      })
      console.log('海康-实时-realtimeVideo')
    }
    //回放
    function playback() {
      list.startTime = list.startTime || list.alarmTime
      var cameraIndexCode = list.deviceCode //获取输入的监控点编号值，必填
      var startTimeStamp = new Date(
        dateFormat(
          new Date((list.startTime || '').replace(/-/g, '/')),
          'yyyy/MM/dd hh:mm:ss'
        )
      ).getTime() //回放查询开始时间戳，必填
      var endTimeStamp = new Date(
        dateFormat(
          new Date((list.endTime || '').replace(/-/g, '/')),
          'yyyy/MM/dd hh:mm:ss'
        )
      ).getTime() //回放结束时间戳，必填
      var recordLocation = list.deviceLocation === '0' ? 0 : 1 //录像存储位置：0-中心存储，1-设备存储
      var transMode = 1 //传输协议：0-UDP，1-TCP
      var gpuMode = 0 //是否启用GPU硬解，0-不启用，1-启用
      var wndId = -1 //播放窗口序号（在2x2以上布局下可指定播放窗口）

      var params = {
        cameraIndexCode: cameraIndexCode, //监控点编号
        startTimeStamp: Math.floor(startTimeStamp / 1000).toString(), //录像查询开始时间戳，单位：秒
        endTimeStamp: Math.floor(endTimeStamp / 1000).toString(), //录像结束开始时间戳，单位：秒
        recordLocation: recordLocation, //录像存储类型：0-中心存储，1-设备存储
        transMode: transMode, //传输协议：0-UDP，1-TCP
        gpuMode: gpuMode, //是否启用GPU硬解，0-不启用，1-启用
        wndId: wndId //可指定播放窗口
      }
      console.log('海康-回放-params', params)
      oWebControl.JS_RequestInterface({
        funcName: 'startPlayback',
        argument: JSON.stringify(params)
      })
    }
    // 格式化时间
    function dateFormat(oDate, fmt) {
      var o = {
        'M+': oDate.getMonth() + 1, //月份
        'd+': oDate.getDate(), //日
        'h+': oDate.getHours(), //小时
        'm+': oDate.getMinutes(), //分
        's+': oDate.getSeconds(), //秒
        'q+': Math.floor((oDate.getMonth() + 3) / 3), //季度
        S: oDate.getMilliseconds() //毫秒
      }
      if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          (oDate.getFullYear() + '').substr(4 - RegExp.$1.length)
        )
      }
      for (var k in o) {
        if (new RegExp('(' + k + ')').test(fmt)) {
          fmt = fmt.replace(
            RegExp.$1,
            RegExp.$1.length == 1
              ? o[k]
              : ('00' + o[k]).substr(('' + o[k]).length)
          )
        }
      }
      return fmt
    }
    //停止全部预览
    $('#stopAllPreview').click(function () {
      stopVideo()
    })

    $(window).unload(function () {
      destroy()
    })
    // 标签关闭
    function destroy(next) {
      try {
        if (oWebControl != null) {
          // stopVideo();
          oWebControl.JS_HideWnd() // 先让窗口隐藏，规避可能的插件窗口滞后于浏览器消失问题
          if (!next) {
            window.parent.postMessage({
              message: {
                eventType: 'destroy',
                id: faterNodeId,
                index: Number(areaId?.split('_')[1])
              }
            })
          }
          oWebControl.JS_Disconnect().then(
            function () {
              // 断开与插件服务连接成功
              console.log('destroy')
              if (next) {
                // 切换为实时或回放
                window.parent.postMessage({
                  message: {
                    eventType: 'loading',
                    id: faterNodeId,
                    index: Number(areaId?.split('_')[1])
                  }
                })
                setTimeout(() => {
                  initPlugin()
                }, 500)
              }
            },
            function () {
              // 断开与插件服务连接失败
            }
          )
        }
      } catch (e) {
        //TODO handle the exception
      }
    }
    // 停止播放
    function stopVideo() {
      if (oWebControl) {
        oWebControl.JS_RequestInterface({
          funcName: list.isplayback == 1 ? 'stopAllPreview' : 'stopAllPlayback'
        })
      }
    }
    //获取公钥
    function getPubKey(callback) {
      oWebControl
        .JS_RequestInterface({
          funcName: 'getRSAPubKey',
          argument: JSON.stringify({
            keyLength: 1024
          })
        })
        .then(function (oData) {
          // console.log(oData);
          if (oData.responseMsg.data) {
            pubKey = oData.responseMsg.data
            callback()
          }
        })
    }

    //RSA加密
    function setEncrypt(value) {
      var encrypt = new JSEncrypt()
      encrypt.setPublicKey(pubKey)
      return encrypt.encrypt(value)
    }
    // 父容器宽高变化
    function resize() {
      if (!oWebControl || !oWebControl.JS_SetDocOffset) return
      try {
        oWebControl.JS_SetDocOffset({
          left: offsetLeft,
          top: offsetTop
        }) // 更新插件窗口位置
        oWebControl.JS_Resize(w, h) // 初始化后resize一次，规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
        // setWndCover();
      } catch (e) {
        console.log(e.message)
      }
    }

    // 监听resize事件，使插件窗口尺寸跟随DIV窗口变化
    $(window).resize(function () {
      if (oWebControl != null) {
        oWebControl.JS_Resize(w, h)
        setWndCover()
      }
    })

    // 监听滚动条scroll事件，使插件窗口跟随浏览器滚动而移动
    $(window).scroll(function () {
      if (oWebControl != null) {
        oWebControl.JS_Resize(w, h)
        setWndCover()
      }
    })

    // 设置窗口裁剪，当因滚动条滚动导致窗口需要被遮住的情况下需要JS_CuttingPartWindow部分窗口
    function setWndCover() {
      try {
        var iWidth = $(window).width()
        var iHeight = $(window).height()
        var oDivRect = $('#playWnd').get(0).getBoundingClientRect()

        var iCoverLeft = oDivRect.left < 0 ? Math.abs(oDivRect.left) : 0
        var iCoverTop = oDivRect.top < 0 ? Math.abs(oDivRect.top) : 0
        var iCoverRight =
          oDivRect.right - iWidth > 0 ? Math.round(oDivRect.right - iWidth) : 0
        var iCoverBottom =
          oDivRect.bottom - iHeight > 0
            ? Math.round(oDivRect.bottom - iHeight)
            : 0

        iCoverLeft = iCoverLeft > w ? w : iCoverLeft
        iCoverTop = iCoverTop > h ? h : iCoverTop
        iCoverRight = iCoverRight > w ? w : iCoverRight
        iCoverBottom = iCoverBottom > h ? h : iCoverBottom

        oWebControl.JS_RepairPartWindow(0, 0, w + 1, h) // 多1个像素点防止还原后边界缺失一个像素条
        if (iCoverLeft != 0) {
          oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, h)
        }
        if (iCoverTop != 0) {
          oWebControl.JS_CuttingPartWindow(0, 0, w + 1, iCoverTop) // 多剪掉一个像素条，防止出现剪掉一部分窗口后出现一个像素条
        }
        if (iCoverRight != 0) {
          oWebControl.JS_CuttingPartWindow(w - iCoverRight, 0, iCoverRight, h)
        }
        if (iCoverBottom != 0) {
          oWebControl.JS_CuttingPartWindow(0, h - iCoverBottom, w, iCoverBottom)
        }
      } catch (e) {
        //TODO handle the exception
      }
    }
  </script>
</html>
